#pragma once
#include "Header.h"
#include <stdio.h>
#include <string.h>

//
//  CStrTraits
//

template <typename T = char>
class CStrTraits
{
public:
    typedef char XCHAR;
    typedef LPSTR PXSTR;
    typedef LPCSTR PCXSTR;
    typedef wchar_t YCHAR;
    typedef LPWSTR PYSTR;
    typedef LPCWSTR PCYSTR;
};

template <>
class CStrTraits<wchar_t>
{
public:
    typedef wchar_t XCHAR;
    typedef LPWSTR PXSTR;
    typedef LPCWSTR PCXSTR;
    typedef char YCHAR;
    typedef LPSTR PYSTR;
    typedef LPCSTR PCYSTR;
};

//
//  CCrtTraits
//

template <typename T = char>
class CCrtTraits : public CStrTraits<char>
{
public:
    static int GetStrLength(IN LPCSTR pszSrc) { return strlen(pszSrc); }
    static int GetStrLength(IN LPCWSTR pszSrc) { return ::WideCharToMultiByte(CP_ACP, 0, pszSrc, -1, nullptr, 0, nullptr, nullptr) - 1; }
    static void ConvertToBaseType(OUT LPSTR pszDest, IN int nDestLength, IN LPCWSTR pszSrc, IN int nSrcLength = -1) {
        ::WideCharToMultiByte(CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength, nullptr, nullptr);
    }
    static int GetFormatLength(IN LPCSTR pszFormat, IN va_list args) {
        return _vscprintf(pszFormat, args);
    }
    static int Format(OUT LPSTR pszBuffer, IN size_t nlength, IN LPCSTR pszFormat, IN va_list args) {
        return vsprintf_s(pszBuffer, nlength, pszFormat, args);
    }

    static int Compare(IN LPCSTR pszA, IN LPCSTR pszB) {
        return strcmp(pszA, pszB);
    }

    static int CompareNoCase(IN LPCSTR pszA, IN LPCSTR pszB) {
        return _stricmp(pszA, pszB);
    }

    static LPSTR Uppercase(IN OUT LPSTR psz, IN size_t size) {
        errno_t err = _strupr_s(psz, size);
        return (err == 0) ? psz : nullptr;
    }

    static LPSTR Lowercase(IN OUT LPSTR psz, IN size_t size) {
        errno_t err = _strlwr_s(psz, size);
        return (err == 0) ? psz : nullptr;
    }

    static LPSTR Reverse(IN OUT LPSTR psz) {
        return _strrev(psz);
    }

	static LPCSTR FindSubStr( IN LPCSTR psz, IN LPCSTR pszSub) {
        return strstr(psz, pszSub);
	}

	static LPSTR FindSubStr( IN LPSTR psz, IN LPCSTR pszSub) {
        return strstr(psz, pszSub);
	}

	static LPCSTR FindSubChr( IN LPCSTR psz, IN char chSub) {
        return strchr(psz, chSub);
	}

    static LPCSTR FindChrFromSet(IN LPCSTR psz, IN LPCSTR pszSet) {
        return strpbrk(psz, pszSet);
    }

    static LPCSTR FindChrFromEnd(IN LPCSTR psz, IN char ch) {
        return strrchr(psz, ch);
    }

    static int IsSpace(IN char ch) {
        return isspace(ch);
    }
};

template <>
class CCrtTraits<wchar_t> : public CStrTraits<wchar_t>
{
public:
    static int GetStrLength(IN LPCSTR pszSrc) { return ::MultiByteToWideChar(CP_ACP, 0, pszSrc, -1, nullptr, 0) - 1; }
    static int GetStrLength(IN LPCWSTR pszSrc) { return wcslen(pszSrc); }
    static void ConvertToBaseType(OUT LPWSTR pszDest, IN int nDestLength, IN LPCSTR pszSrc, IN int nSrcLength = -1) {
        ::MultiByteToWideChar(CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength);
    }
    static int GetFormatLength(IN LPCWSTR pszFormat, IN va_list args) {
        return _vscwprintf(pszFormat, args);
    }
    static int Format(OUT LPWSTR pszBuffer, IN size_t nLength, IN LPCWSTR pszFormat, IN va_list args) {
        return vswprintf_s(pszBuffer, nLength, pszFormat, args);
    }

    static int Compare(IN LPCWSTR pszA, IN LPCWSTR pszB) {
        return wcscmp(pszA, pszB);
    }

    static int CompareNoCase(IN LPCWSTR pszA, IN LPCWSTR pszB) {
        return _wcsicmp(pszA, pszB);
    }

    static LPWSTR Uppercase(IN OUT LPWSTR psz, IN size_t size) {
        errno_t err = _wcsupr_s(psz, size);
        return (err == 0) ? psz : nullptr;
    }

    static LPWSTR Lowercase(IN OUT LPWSTR psz, IN size_t size) {
        errno_t err = _wcslwr_s(psz, size);
        return (err == 0) ? psz : nullptr;
    }

    static LPWSTR Reverse(IN OUT LPWSTR psz) {
        return _wcsrev(psz);
    }

    static LPCWSTR FindSubStr(IN LPCWSTR psz, IN LPCWSTR pszSub) {
        return wcsstr(psz, pszSub);
    }

    static LPWSTR FindSubStr(IN LPWSTR psz, IN LPCWSTR pszSub) {
        return wcsstr(psz, pszSub);
    }

    static LPCWSTR FindSubChr(IN LPCWSTR psz, IN wchar_t chSub) {
        return wcschr(psz, chSub);
    }

    static LPCWSTR FindChrFromSet(IN LPCWSTR psz, IN LPCWSTR pszSet) {
        return wcspbrk(psz, pszSet);
    }

    static LPCWSTR FindChrFromEnd(IN LPCWSTR psz, IN wchar_t ch) {
        return wcsrchr(psz, ch);
    }

    static int IsSpace(IN wchar_t ch) {
        return iswspace(ch);
    }
};
